package labox.innovation.gameserver;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Calendar;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import labox.innovation.config.Config;
import labox.innovation.config.Server;
import labox.innovation.db.core.L2DatabaseFactory;
import labox.innovation.gameserver.cache.HtmCache;
import labox.innovation.gameserver.datatables.AdminCommandAccessRights;
import labox.innovation.gameserver.datatables.CharNameTable;
import labox.innovation.gameserver.datatables.Experience;
import labox.innovation.gameserver.datatables.Repair;
import labox.innovation.gameserver.datatables.ShopItemsListConfig;
import labox.innovation.gameserver.datatables.SkillTable;
import labox.innovation.gameserver.datatables.SkillTreeTable;
import labox.innovation.gameserver.datatables.TeleportCostsConfig;
import labox.innovation.gameserver.datatables.TeleportLocationTable;
import labox.innovation.gameserver.idfactory.IdFactory;
import labox.innovation.gameserver.instancemanager.InstanceManager;
import labox.innovation.gameserver.model.ConsignmentManager;
import labox.innovation.gameserver.model.FuzeWorld;
import labox.innovation.gameserver.model.L2PartyManager;
import labox.innovation.gameserver.model.base.PracticeId;
import labox.innovation.gameserver.model.quest.dataset.JQuestXMLParse;
import labox.innovation.gameserver.network.L2GameClient;
import labox.innovation.gameserver.network.L2GamePacketHandler;
import labox.innovation.gameserver.pathfinding.PathFinding;
import labox.innovation.gameserver.rank.RankTask;
import labox.innovation.gameserver.scripting.L2ScriptEngineManager;
import labox.innovation.gameserver.taskmanager.AutoAnnounceTaskManager;
import labox.innovation.gameserver.taskmanager.AutoCountPlayersManager;
import labox.innovation.gameserver.taskmanager.SyncLocationTaskManager;
import labox.innovation.netcore.SelectorConfig;
import labox.innovation.netcore.SelectorThread;
import labox.innovation.pay.DepositConfig;
import labox.innovation.pay.http.RechargeManager;
import labox.innovation.pay.http.RechargePacketHelper;
import labox.innovation.status.Status;
import labox.innovation.util.DeadLockDetector;

/**
 * 游戏入口
 * 
 * @version $Revision: 1.29.2.15.2.19 $ $Date: 2005/04/05 19:41:23 $
 */
public class GameServer {

	private static final Logger _log = LoggerFactory.getLogger(GameServer.class.getName());

	/**
	 * 选择器线程
	 */
	private final SelectorThread<L2GameClient> _selectorThread;

	/**
	 * 死锁检查线程
	 */
	private final DeadLockDetector _deadDetectThread;

	/**
	 * id工厂实例
	 */
	private final IdFactory _idFactory;

	/**
	 * GameServer单子
	 */
	public static GameServer gameServer;

	/**
	 * 登录服务器连接处理线程
	 */
	private LoginServerThread _loginThread;

	/**
	 * telnet线程
	 */
	private static Status _statusServer;

	public static final Calendar dateTimeServerStarted = Calendar.getInstance();

	public final L2GamePacketHandler gph;

	/**
	 * 获取使用的内存量（MB）
	 * 
	 * @return
	 */
	public long getUsedMemoryMB() {
		return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1048576;
	}

	/**
	 * 获取网络连接选择器
	 * 
	 * @return
	 */
	public SelectorThread<L2GameClient> getSelectorThread() {
		return _selectorThread;
	}

	/**
	 * 获取死锁检查线程
	 * 
	 * @return
	 */
	public DeadLockDetector getDeadLockDetectorThread() {
		return _deadDetectThread;
	}

	/**
	 * 游戏服务器启动入口
	 * 
	 * @throws Exception
	 */
	public GameServer() throws Exception {
		long serverLoadStart = System.currentTimeMillis();

		gameServer = this;
		_log.info("used mem:" + getUsedMemoryMB() + "MB", Config.SERVER_ID, "启动内存占用");

		if (Config.SERVER_VERSION != null) {
			_log.info("Innovation Server Version:" + Config.SERVER_VERSION, Config.SERVER_ID, "服务器版本");
		}
		if (Config.DATAPACK_VERSION != null) {
			_log.info("Innovation Datapack Version:" + Config.DATAPACK_VERSION, Config.SERVER_ID, "数据包版本");
		}

		// ID 工厂初始化
		_idFactory = IdFactory.getInstance();

		if (!_idFactory.isInitialized()) {
			_log.error("Could not read object IDs from DB. Please Check Your Data.", Config.SERVER_ID, new Exception("Could not initialize the ID factory"));
			throw new Exception("Could not initialize the ID factory");
		}

		// 数据库连接工厂初始化
	//	L2DatabaseFactory.getInstance();

		// 线程池初始化
		ThreadPoolManager.getInstance();

		// 脚本引擎初始化
	//	L2ScriptEngineManager.getInstance();

		// 游戏时间控制器初始化
		//GameTimeController.getInstance();

		// 初始化经验值表
		//Experience.getInstance();

		// 所有游戏中玩家名称查询表
		//CharNameTable.getInstance();// 玩家注册的角色名表

		// 初始化仙魔位表
		//PracticeId.loadPractice();

		//SkillTable.getInstance();

		// ItemTable.getInstance();
		// if (!ItemTable.getInstance().isInitialized()) {
		// _log.severe("Could not find the extraced files. Please Check Your Data.");
		// throw new Exception("Could not initialize the item table");
		// }
		// 游戏世界管理器
		//FuzeWorld.getInstance().load();

		//SyncLocationTaskManager.getInstance();// 世界角色坐标同步任务

		// ZoneManager.getInstance();//区域的内部地带管理

		//InstanceManager.getInstance();// 副本管理

		//SkillTreeTable.getInstance();// 技能树
		//		
		// PetSkillsTable.getInstance();//宠物技能树
		//		
		// ArmorSetsTable.getInstance();//装备配置
		//		
		// SkillSpellbookTable.getInstance();//技能学习书

		// Call to load caches
		//HtmCache.getInstance();// 所有的html中string缓存的管理

		// CrestCache.getInstance();

		// forums has to be loaded before clan data, because of last forum id
		// used should have also memo included
		// if (Config.COMMUNITY_TYPE > 0)
		// ForumsBBSManager.getInstance().initRoot();

		// ClanTable.getInstance();

		//PathFinding.getInstance();

		//TeleportLocationTable.getInstance();

		//Announcements.getInstance();// 登陆公告管理

		//AutoAnnounceTaskManager.getInstance();// 自动公告管理器
		//L2PartyManager.getInstance();// 管理组队情况下离线的玩家
		//ConsignmentManager.getInstance();// 加载寄售物品
		/** Load Manager */

		// QuestManager.getInstance();

		// TransformationManager.getInstance();
		// L2FriendsNewsTaskManager.getInstance();//关于好友动态消息管理类

//		try {
//			_log.info("Loading Server Scripts", Config.SERVER_ID, "脚本");
//			File scripts = new File(Config.DATAPACK_ROOT, "/data/scripts.cfg");
//			if (!Config.ALT_DEV_NO_QUESTS)
//				L2ScriptEngineManager.getInstance().executeScriptList(scripts);
//		} catch (IOException ioe) {
//			_log.error("Failed loading scripts.cfg, no script going to be loaded", Config.SERVER_ID, ioe);
//		}

		// 解析任务XML模板
		//JQuestXMLParse.getInstance();
		// QuestManager.getInstance().report();

		// TransformationManager.getInstance().report();//变形管理器报告

		// if (Config.SAVE_DROPPED_ITEM)
		// ItemsOnGroundManager.getInstance();

		// if (Config.AUTODESTROY_ITEM_AFTER > 0 ||
		// Config.HERB_AUTO_DESTROY_TIME > 0)
		// ItemsAutoDestroy.getInstance();

		// FaenorScriptEngine.getInstance();

		// AdminCommandHandler.getInstance();
		// 道具逻辑处理器
		// ItemHandler.getInstance();
		// 技能逻辑处理器
		// SkillHandler.getInstance();

		//Repair.getInstance(); // -- 载入修理配置信息
		//ShopItemsListConfig.getInstance(); // -- 载入商城配置信息
		//TeleportCostsConfig.getInstance(); // -- 载入传送价格配置
		//AdminCommandAccessRights.getInstance(); // -- 载入GM权限命令配置
		//RankTask.getInstance().getStart(); // -- 开启定时刷新排行榜信息任务

		// 用户命令处理器
		// UserCommandHandler.getInstance();

		// AccessLevels.getInstance();

		// AdminCommandAccessRights.getInstance();

		// 结婚系统管理器
		// CoupleManager.getInstance();

		// TaskManager.getInstance();

		// GmListTable.getInstance();

		// read pet stats from db
		// L2PetDataTable.getInstance().loadPetsData();

		// 向虚拟机的关闭队列注册一个关闭钩子
		Runtime.getRuntime().addShutdownHook(Shutdown.getInstance());

		// 启动充值系统
		//RechargeManager.getInstance().start();
		// 启动 统计在线用户数
		//AutoCountPlayersManager.getInstance();
		
		
		
		// 游戏主线程初始化
		//Engine.getInstance().start();
		
		if (Config.DEADLOCK_DETECTOR) {
			_deadDetectThread = new DeadLockDetector();
		} else
			_deadDetectThread = null;
		System.gc();
		// maxMemory is the upper limit the jvm can use, totalMemory the size of
		// the current allocation pool, freeMemory the unused memory in the
		// allocation pool
		long freeMem = (Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory() + Runtime.getRuntime().freeMemory()) / 1048576;
		long totalMem = Runtime.getRuntime().maxMemory() / 1048576;
		_log.info("GameServer Started, free memory " + freeMem + " Mb of " + totalMem + " Mb", Config.SERVER_ID, "内存情况");

		//_loginThread = LoginServerThread.getInstance(); // -- 处理与登陆服务器通信线程
		//_loginThread.start();

		final SelectorConfig sc = new SelectorConfig();
		sc.MAX_READ_PER_PASS = Config.NETCORE_MAX_READ_PER_PASS;
		sc.MAX_SEND_PER_PASS = Config.NETCORE_MAX_SEND_PER_PASS;
		sc.SLEEP_TIME = Config.NETCORE_SELECTOR_SLEEP_TIME;
		sc.HELPER_BUFFER_COUNT = Config.NETCORE_HELPER_BUFFER_COUNT;

		gph = new L2GamePacketHandler(); // -- 处理与玩家客户端之间通信
		_selectorThread = new SelectorThread<L2GameClient>(sc, gph, gph, gph, gph);

		InetAddress bindAddress = null;
		if (!Config.GAMESERVER_HOSTNAME.equals("*")) {
			try {
				bindAddress = InetAddress.getByName(Config.GAMESERVER_HOSTNAME);
			} catch (UnknownHostException e1) {
				_log.error("WARNING: The GameServer bind address is invalid, using all avaliable IPs. Reason: " + e1.getMessage(), Config.SERVER_ID, e1);

				if (Config.DEVELOPER) {
					e1.printStackTrace();
				}
			}
		}

		try {
			_selectorThread.openServerSocket(bindAddress, Config.PORT_GAME);
		} catch (IOException e) {
			_log.error("FATAL: Failed to open server socket. Reason: " + e.getMessage(), Config.SERVER_ID, e);
			if (Config.DEVELOPER) {
				e.printStackTrace();
			}
			System.exit(1);
		}
		_selectorThread.start();
		_log.info("Maximum Numbers of Connected Players: " + Config.MAXIMUM_ONLINE_USERS, Config.SERVER_ID, "人数上限");
		long serverLoadEnd = System.currentTimeMillis();
		_log.info("Server Loaded in " + ((serverLoadEnd - serverLoadStart) / 1000) + " seconds", Config.SERVER_ID, "启动消耗时间");
	}

	public static void main(String[] args) throws Exception {
		try {

			Server.serverMode = Server.MODE_GAMESERVER;
			// Initialize config
			Config.load();
			// L2DatabaseFactory.getInstance();
			gameServer = new GameServer();

			if (Config.IS_TELNET_ENABLED) {
				_statusServer = new Status(Server.serverMode);
				_statusServer.start();
			} else {
				_log.info("Telnet server is currently disabled.", Config.SERVER_ID, "Telnet情况");
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}
